﻿//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Query Application Block
//===============================================================================

using System;
using System.Data;
using System.Collections.Generic;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using EntLibContrib.Query.Instrumentation;
using EntLibContrib.Query.Configuration;
using EntLibContrib.Query.Commands;
using EntLibContrib.Query.Properties;

namespace EntLibContrib.Query.Queries
{
	/// <summary>
	/// Wcf Service Query.
	/// </summary>
	/// <remarks>
	/// This provider creates a query for a Wcf Service.
	/// </remarks>
	[ConfigurationElementType(typeof(WcfServiceQueryData))]
	public class WcfServiceQuery : ServiceQuery
	{
		#region Fields
		private string endpoint;
		#endregion

		#region Construction
		/// <summary>
		/// Initializes a new default instance of the <see cref="WcfServiceQuery"/> class.
		/// </summary>
		/// <param name="name">The query name.</param>
		/// <param name="endpoint">The service end point.</param>
		/// <param name="address">The service address.</param>
		/// <param name="service">The service type name.</param>
		/// <param name="method">The service method.</param>
		/// <param name="customCommand">The custom command.</param>
		/// <param name="parameterSet">The parameter set.</param>
		/// <param name="instrumentationProvider">The instrumentation provider.</param>
		public WcfServiceQuery(string name,
													string endpoint,
													string address,
													string service,
													string method,
													ICustomCommand customCommand,
													IParameterSet parameterSet,
													QueryInstrumentationProvider instrumentationProvider)
			: base(name, address, service, method, customCommand, parameterSet, instrumentationProvider)
		{
			ValidateAndStoreParameters(endpoint);
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Executes a read command and returns the results.
		/// </summary>
		/// <param name="parameterValues">The parameter values.</param>
		/// <returns>
		/// Dataset containing the results of the read operation
		/// </returns>
		/// <remarks>
		/// 	<para>This method takes the parameter values from the given dictionary.</para>
		/// 	<para>Output parameters will update the parameter property values.</para>
		/// </remarks>
		public override DataSet ExecuteForRead(IDictionary<string, object> parameterValues)
		{
			try
			{
				// set the parameter values given in the dictionary
				if (parameterValues != null)
					SetParameterValues(parameterValues);

				// invoke the service method which must return a DataSet
				DataSet results = BuildCommand().ExecuteForRead();

				// update the instrumentation counters
				UpdateReadCounters(results);

				// return the results
				return results;
			}
			catch (Exception exception)
			{
				// log and rethrow the error
				LogReadError(exception);
				throw;
			}
		}

		/// <summary>
		/// Executes a write command and saves data to the data source.
		/// </summary>
		/// <param name="parameterValues">The parameter values.</param>
		/// <remarks>
		/// 	<para>This method takes the parameter values from the given dictionary.</para>
		/// 	<para>Output parameters will update the parameter property values.</para>
		/// </remarks>
		public override void ExecuteForWrite(IDictionary<string, object> parameterValues)
		{
			try
			{
				// set the parameter values given in the dictionary
				if (parameterValues != null)
					SetParameterValues(parameterValues);

				// invoke the service method which must return void
				BuildCommand().ExecuteForWrite();

				// update the instrumentation counters
				UpdateWriteCounters();
			}
			catch (Exception exception)
			{
				// log and rethrow the error
				LogWriteError(exception);
				throw;
			}
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Validates the and store parameters.
		/// </summary>
		/// <param name="endpointName">Name of the endpoint.</param>
		private void ValidateAndStoreParameters(string endpointName)
		{
			// check for a null or empty path name
			if (string.IsNullOrEmpty(endpointName))
				throw new ArgumentNullException("endpointName", InternalResources.ExceptionWcfServiceQueryEndpointNullOrEmpty);

			// store the end point
			this.endpoint = endpointName;
		}

		/// <summary>
		/// Builds the command to be invoked.
		/// </summary>
		/// <returns>An <see cref="ICommand"/> object</returns>
		protected override ICommand BuildCommand()
		{
			// check for a custom command
			if (CustomCommand == null)
				return new WcfServiceCommand(endpoint, Address, Service, Method, ParameterSet.Parameters);
			else
			{
				ServiceCommand customServiceCommand = (ServiceCommand)(CustomCommand.Command);
				customServiceCommand.Endpoint = endpoint;
				customServiceCommand.Address = Address;
				customServiceCommand.Service = Service;
				customServiceCommand.Method = Method;
				customServiceCommand.AddParameters(ParameterSet.Parameters);
				return customServiceCommand;
			}
		}
		#endregion
	}
}
